package ch.dreamweb.readpractice.client.lesetraining;

import java.util.ArrayList;

import ch.dreamweb.readpractice.client.lesetraining.meta.event.StartLoginEvent;
import ch.dreamweb.readpractice.client.lesetraining.meta.event.StartLoginEventHandler;
import ch.dreamweb.readpractice.client.lesetraining.meta.event.StartMetaEvent;
import ch.dreamweb.readpractice.client.lesetraining.meta.event.StartMetaEventHandler;
import ch.dreamweb.readpractice.client.lesetraining.meta.presenter.LoginPresenter;
import ch.dreamweb.readpractice.client.lesetraining.meta.presenter.Presenter;
import ch.dreamweb.readpractice.client.lesetraining.meta.view.LoginView;
import ch.dreamweb.readpractice.client.lesetraining.meta.view.LoginViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartMetaTestEvent;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartMetaTestEventHandler;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartTest1Event;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartTest1EventHandler;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartTest2Event;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartTest2EventHandler;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartTest3Event;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartTest3EventHandler;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartTest4Event;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartTest4EventHandler;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartTest5Event;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartTest5EventHandler;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartTest6Event;
import ch.dreamweb.readpractice.client.lesetraining.test.event.StartTest6EventHandler;
import ch.dreamweb.readpractice.client.lesetraining.test.presenter.MetaTestPresenter;
import ch.dreamweb.readpractice.client.lesetraining.test.presenter.Test1Presenter;
import ch.dreamweb.readpractice.client.lesetraining.test.presenter.Test2Presenter;
import ch.dreamweb.readpractice.client.lesetraining.test.presenter.Test3Presenter;
import ch.dreamweb.readpractice.client.lesetraining.test.presenter.Test4Presenter;
import ch.dreamweb.readpractice.client.lesetraining.test.presenter.Test5Presenter;
import ch.dreamweb.readpractice.client.lesetraining.test.presenter.Test6Presenter;
import ch.dreamweb.readpractice.client.lesetraining.test.view.MetaTestView;
import ch.dreamweb.readpractice.client.lesetraining.test.view.MetaTestViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.test.view.Test1View;
import ch.dreamweb.readpractice.client.lesetraining.test.view.Test1ViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.test.view.Test2View;
import ch.dreamweb.readpractice.client.lesetraining.test.view.Test2ViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.test.view.Test3View;
import ch.dreamweb.readpractice.client.lesetraining.test.view.Test3ViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.test.view.Test4View;
import ch.dreamweb.readpractice.client.lesetraining.test.view.Test4ViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.test.view.Test5View;
import ch.dreamweb.readpractice.client.lesetraining.test.view.Test5ViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.test.view.Test6View;
import ch.dreamweb.readpractice.client.lesetraining.test.view.Test6ViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.train.event.StartUnit1Event;
import ch.dreamweb.readpractice.client.lesetraining.train.event.StartUnit1EventHandler;
import ch.dreamweb.readpractice.client.lesetraining.train.event.StartUnit2Event;
import ch.dreamweb.readpractice.client.lesetraining.train.event.StartUnit2EventHandler;
import ch.dreamweb.readpractice.client.lesetraining.train.event.StartUnit3Event;
import ch.dreamweb.readpractice.client.lesetraining.train.event.StartUnit3EventHandler;
import ch.dreamweb.readpractice.client.lesetraining.train.event.StartUnit4Event;
import ch.dreamweb.readpractice.client.lesetraining.train.event.StartUnit4EventHandler;
import ch.dreamweb.readpractice.client.lesetraining.train.presenter.MetaPresenter;
import ch.dreamweb.readpractice.client.lesetraining.train.presenter.Unit1Presenter;
import ch.dreamweb.readpractice.client.lesetraining.train.presenter.Unit2Presenter;
import ch.dreamweb.readpractice.client.lesetraining.train.presenter.Unit3Presenter;
import ch.dreamweb.readpractice.client.lesetraining.train.presenter.Unit4Presenter;
import ch.dreamweb.readpractice.client.lesetraining.train.view.MetaView;
import ch.dreamweb.readpractice.client.lesetraining.train.view.MetaViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.train.view.Unit1View;
import ch.dreamweb.readpractice.client.lesetraining.train.view.Unit1ViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.train.view.Unit2View;
import ch.dreamweb.readpractice.client.lesetraining.train.view.Unit2ViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.train.view.Unit3View;
import ch.dreamweb.readpractice.client.lesetraining.train.view.Unit3ViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.train.view.Unit4View;
import ch.dreamweb.readpractice.client.lesetraining.train.view.Unit4ViewImpl;
import ch.dreamweb.readpractice.client.lesetraining.widget.MessageDialog;
import ch.dreamweb.readpractice.client.managed.request.ApplicationRequestFactory;
import ch.dreamweb.readpractice.shared.InfoHolder;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.RootPanel;

public class AppController implements Presenter, ValueChangeHandler<String> {
	private static final String META = "meta";
	private static final String METATEST = "metatest";
	private static final String UNIT4 = "unit4";
	private static final String UNIT3 = "unit3";
	private static final String UNIT2 = "unit2";
	private static final String UNIT1 = "unit1";
	private static final String TEST1 = "test1";
	private static final String TEST2 = "test2";
	private static final String TEST3 = "test3";
	private static final String TEST4 = "test4";
	private static final String TEST5 = "test5";
	private static final String TEST6 = "test6";
	private static final String LOGIN = "login";
	private final EventBus eventBus;
	private final TrainingServiceAsync rpcService;
	private HasWidgets container;
	private Unit1View unit1View = null;
	private Unit2View unit2View = null;
	private Unit3View unit3View = null;
	private Unit4View unit4View = null;
	private Test1View test1View = null;
	private Test2View test2View = null;
	private Test3View test3View = null;
	private Test4View test4View = null;
	private Test5View test5View = null;
	private Test6View test6View = null;
	private MetaView metaView = null;
	private MetaTestView metaTestView = null;
	private LoginView loginView = null;
	private Unit1Presenter unit1Presenter = null;
	private Unit2Presenter unit2Presenter = null;
	private Unit3Presenter unit3Presenter = null;
	private Unit4Presenter unit4Presenter = null;
	private Test1Presenter test1Presenter = null;
	private Test2Presenter test2Presenter = null;
	private Test3Presenter test3Presenter = null;
	private Test4Presenter test4Presenter = null;
	private Test5Presenter test5Presenter = null;
	private Test6Presenter test6Presenter = null;
	private MetaPresenter metaPresenter = null;
	private MetaTestPresenter metaTestPresenter = null;
	private LoginPresenter loginPresenter = null;
	private final MessageDialog dialogBox = new MessageDialog();
	private final InfoHolder info = InfoHolder.getInstance();
	private final RootPanel loading;
	private final ApplicationRequestFactory requests;

	public AppController(TrainingServiceAsync rpcService, EventBus eventBus,
			RootPanel loading) {
		this.rpcService = rpcService;
		this.loading = loading;
		this.eventBus = eventBus;
		requests = GWT.create(ApplicationRequestFactory.class);
		requests.initialize(eventBus);
		bind();
		loadMorphems();
	}

	private void bind() {
		History.addValueChangeHandler(this);

		eventBus.addHandler(StartUnit1Event.TYPE, new StartUnit1EventHandler() {

			@Override
			public void onStartUnit1(StartUnit1Event event) {
				doStartUnit1();
			}
		});

		eventBus.addHandler(StartUnit2Event.TYPE, new StartUnit2EventHandler() {

			@Override
			public void onStartUnit2(StartUnit2Event event) {
				doStartUnit2();
			}
		});

		eventBus.addHandler(StartUnit3Event.TYPE, new StartUnit3EventHandler() {

			@Override
			public void onStartUnit3(StartUnit3Event event) {
				doStartUnit3();
			}
		});

		eventBus.addHandler(StartUnit4Event.TYPE, new StartUnit4EventHandler() {

			@Override
			public void onStartUnit4(StartUnit4Event event) {
				doStartUnit4();
			}
		});

		eventBus.addHandler(StartTest1Event.TYPE, new StartTest1EventHandler() {

			@Override
			public void onStartTest1(StartTest1Event event) {
				doStartTest1();
			}
		});

		eventBus.addHandler(StartTest2Event.TYPE, new StartTest2EventHandler() {

			@Override
			public void onStartTest2(StartTest2Event event) {
				doStartTest2();
			}
		});

		eventBus.addHandler(StartTest3Event.TYPE, new StartTest3EventHandler() {

			@Override
			public void onStartTest3(StartTest3Event event) {
				doStartTest3();
			}
		});

		eventBus.addHandler(StartTest4Event.TYPE, new StartTest4EventHandler() {

			@Override
			public void onStartTest4(StartTest4Event event) {
				doStartTest4();
			}
		});

		eventBus.addHandler(StartTest5Event.TYPE, new StartTest5EventHandler() {

			@Override
			public void onStartTest5(StartTest5Event event) {
				doStartTest5();
			}
		});

		eventBus.addHandler(StartTest6Event.TYPE, new StartTest6EventHandler() {

			@Override
			public void onStartTest6(StartTest6Event event) {
				doStartTest6();
			}
		});

		eventBus.addHandler(StartMetaEvent.TYPE, new StartMetaEventHandler() {

			@Override
			public void onStartMeta(StartMetaEvent event) {
				doStartMeta();
			}
		});

		eventBus.addHandler(StartMetaTestEvent.TYPE,
				new StartMetaTestEventHandler() {

					@Override
					public void onStartMetaTest(StartMetaTestEvent event) {
						doStartMetaTest();
					}
				});

		eventBus.addHandler(StartLoginEvent.TYPE, new StartLoginEventHandler() {

			@Override
			public void onStartLogin(StartLoginEvent event) {
				doStartLogin();
			}
		});
	}

	private void doStartUnit1() {
		History.newItem(UNIT1);
	}

	private void doStartUnit2() {
		History.newItem(UNIT2);
	}

	private void doStartUnit3() {
		History.newItem(UNIT3);
	}

	private void doStartUnit4() {
		History.newItem(UNIT4);
	}

	private void doStartMeta() {
		History.newItem(META);
	}

	private void doStartMetaTest() {
		History.newItem(METATEST);
	}

	private void doStartTest1() {
		History.newItem(TEST1);
	}

	private void doStartTest2() {
		History.newItem(TEST2);
	}

	private void doStartTest3() {
		History.newItem(TEST3);
	}

	private void doStartTest4() {
		History.newItem(TEST4);
	}

	private void doStartTest5() {
		History.newItem(TEST5);
	}

	private void doStartTest6() {
		History.newItem(TEST6);
	}

	private void doStartLogin() {
		History.newItem(LOGIN);
	}

	@Override
	public void go(final HasWidgets container) {

		this.container = container;

	}

	private void loadMorphems() {
		rpcService.getMorphemsShuffled(new AsyncCallback<ArrayList<String>>() {

			@Override
			public void onFailure(Throwable caught) {
				dialogBox.setText(caught.toString());
				dialogBox.center();
			}

			@Override
			public void onSuccess(ArrayList<String> result) {
				info.setMorphems(result);

				if ("".equals(History.getToken())) {
					History.newItem(LOGIN);
				} else {
					History.fireCurrentHistoryState();
				}

				loading.setVisible(false);
			}
		});

	}

	@Override
	public void onValueChange(ValueChangeEvent<String> event) {
		final String token = event.getValue();

		if (token != null) {
			Long id = info.getSettingId();
			if (id == null && !token.equals(LOGIN)) {
				// user is not logged in but wants to access a unit directly
				History.newItem(LOGIN);
			} else {
				if (token.equals(UNIT1)) {
					GWT.runAsync(new RunAsyncCallback() {
						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							//
							if (unit1View == null) {
								unit1View = new Unit1ViewImpl();

							}
							if (unit1Presenter == null) {
								unit1Presenter = new Unit1Presenter(eventBus,
										requests, unit1View);
							}
							unit1Presenter.go(container);
						}
					});
				} else if (token.equals(UNIT2)) {
					GWT.runAsync(new RunAsyncCallback() {

						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							if (unit2View == null) {
								unit2View = new Unit2ViewImpl();
							}
							if (unit2Presenter == null) {
								unit2Presenter = new Unit2Presenter(eventBus,
										requests, unit2View);
							}
							unit2Presenter.go(container);
						}
					});
				} else if (token.equals(UNIT3)) {
					GWT.runAsync(new RunAsyncCallback() {
						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							if (unit3View == null) {
								unit3View = new Unit3ViewImpl();

							}
							if (unit3Presenter == null) {
								unit3Presenter = new Unit3Presenter(eventBus,
										requests, unit3View);
							}
							unit3Presenter.go(container);
						}
					});
				}

				else if (token.equals(UNIT4)) {
					GWT.runAsync(new RunAsyncCallback() {
						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							if (unit4View == null) {
								unit4View = new Unit4ViewImpl();

							}
							if (unit4Presenter == null) {
								unit4Presenter = new Unit4Presenter(eventBus,
										requests, unit4View);
							}
							unit4Presenter.go(container);
						}
					});
				}

				else if (token.equals(META)) {
					GWT.runAsync(new RunAsyncCallback() {

						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							if (metaView == null) {
								metaView = new MetaViewImpl();
							}
							if (metaPresenter == null) {
								metaPresenter = new MetaPresenter(eventBus,
										requests, metaView);
							}
							metaPresenter.go(container);
						}
					});
				}

				else if (token.equals(METATEST)) {
					GWT.runAsync(new RunAsyncCallback() {

						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							if (metaTestView == null) {
								metaTestView = new MetaTestViewImpl();
							}
							if (metaTestPresenter == null) {
								metaTestPresenter = new MetaTestPresenter(
										eventBus, requests, metaTestView);
							}
							metaTestPresenter.go(container);
						}
					});
				}

				else if (token.equals(TEST1)) {
					GWT.runAsync(new RunAsyncCallback() {
						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							if (test1View == null) {
								test1View = new Test1ViewImpl();

							}
							if (test1Presenter == null) {
								test1Presenter = new Test1Presenter(eventBus,
										requests, test1View);
							}
							test1Presenter.go(container);
						}
					});
				}

				else if (token.equals(TEST2)) {
					GWT.runAsync(new RunAsyncCallback() {
						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							if (test2View == null) {
								test2View = new Test2ViewImpl();

							}
							if (test2Presenter == null) {
								test2Presenter = new Test2Presenter(eventBus,
										requests, test2View);
							}
							test2Presenter.go(container);
						}
					});
				}

				else if (token.equals(TEST3)) {
					GWT.runAsync(new RunAsyncCallback() {
						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							if (test3View == null) {
								test3View = new Test3ViewImpl();

							}
							if (test3Presenter == null) {
								test3Presenter = new Test3Presenter(eventBus,
										requests, test3View);
							}
							test3Presenter.go(container);
						}
					});
				}

				else if (token.equals(TEST4)) {
					GWT.runAsync(new RunAsyncCallback() {
						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							if (test4View == null) {
								test4View = new Test4ViewImpl();

							}
							if (test4Presenter == null) {
								test4Presenter = new Test4Presenter(eventBus,
										requests, test4View);
							}
							test4Presenter.go(container);
						}
					});
				}

				else if (token.equals(TEST5)) {
					GWT.runAsync(new RunAsyncCallback() {
						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							if (test5View == null) {
								test5View = new Test5ViewImpl();

							}
							if (test5Presenter == null) {
								test5Presenter = new Test5Presenter(eventBus,
										requests, test5View);
							}
							test5Presenter.go(container);
						}
					});
				}

				else if (token.equals(TEST6)) {
					GWT.runAsync(new RunAsyncCallback() {
						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							if (test6View == null) {
								test6View = new Test6ViewImpl();

							}
							if (test6Presenter == null) {
								test6Presenter = new Test6Presenter(eventBus,
										requests, test6View);
							}
							test6Presenter.go(container);
						}
					});
				}

				else if (token.equals(LOGIN)) {
					GWT.runAsync(new RunAsyncCallback() {

						@Override
						public void onFailure(Throwable caught) {
							dialogBox.setText(caught.toString());
							dialogBox.center();
						}

						@Override
						public void onSuccess() {
							// lazily initialize our views, and keep them around
							// to
							// be reused
							if (loginView == null) {
								loginView = new LoginViewImpl();
							}
							if (loginPresenter == null) {
								loginPresenter = new LoginPresenter(eventBus,
										requests, loginView);
							}
							loginPresenter.go(container);
						}
					});
				}
			}
		}
	}

	@Override
	public EventBus getEventBus() {
		return eventBus;
	}

}
